Librerias
if(!require("jsonlite")){install.packages("jsonlite")}
Caricamento del pacchetto richiesto: jsonlite
Avvertimento: il pacchetto ‘jsonlite’ è stato creato con R versione 4.2.3
if(!require("httr")){install.packages("httr")}
Caricamento del pacchetto richiesto: httr
Avvertimento: il pacchetto ‘httr’ è stato creato con R versione 4.2.3
if(!require("data.table")){install.packages("data.table")}
Caricamento del pacchetto richiesto: data.table
data.table 1.14.2 using 2 threads (see ?getDTthreads). Latest news: r-datatable.com
Caricamento pacchetto: ‘data.table’
I seguenti oggetti sono mascherati da ‘package:dplyr’:
between, first, last
if(!require("tidyverse")){install.packages("tidyverse")}
Caricamento del pacchetto richiesto: tidyverse
Avvertimento: il pacchetto ‘tidyverse’ è stato creato con R versione 4.2.3Avvertimento: il pacchetto ‘tibble’ è stato creato con R versione 4.2.3Avvertimento: il pacchetto ‘tidyr’ è stato creato con R versione 4.2.3Avvertimento: il pacchetto ‘readr’ è stato creato con R versione 4.2.3Avvertimento: il pacchetto ‘purrr’ è stato creato con R versione 4.2.3Avvertimento: il pacchetto ‘stringr’ è stato creato con R versione 4.2.3Avvertimento: il pacchetto ‘forcats’ è stato creato con R versione 4.2.3Avvertimento: il pacchetto ‘lubridate’ è stato creato con R versione 4.2.3── Attaching core tidyverse packages ────────────────────────────────────────── tidyverse 2.0.0 ──
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ lubridate 1.9.2 ✔ tibble 3.2.1
✔ purrr 1.0.1 ✔ tidyr 1.3.0
✔ readr 2.1.4 ── Conflicts ──────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ data.table::between() masks dplyr::between()
✖ dplyr::filter() masks stats::filter()
✖ data.table::first() masks dplyr::first()
✖ purrr::flatten() masks jsonlite::flatten()
✖ lubridate::hour() masks data.table::hour()
✖ lubridate::isoweek() masks data.table::isoweek()
✖ dplyr::lag() masks stats::lag()
✖ data.table::last() masks dplyr::last()
✖ lubridate::mday() masks data.table::mday()
✖ lubridate::minute() masks data.table::minute()
✖ lubridate::month() masks data.table::month()
✖ lubridate::quarter() masks data.table::quarter()
✖ lubridate::second() masks data.table::second()
✖ purrr::transpose() masks data.table::transpose()
✖ lubridate::wday() masks data.table::wday()
✖ lubridate::week() masks data.table::week()
✖ lubridate::yday() masks data.table::yday()
✖ lubridate::year() masks data.table::year()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
if(!require("scales")){install.packages("scales")}
Caricamento del pacchetto richiesto: scales
Caricamento pacchetto: ‘scales’
Il seguente oggetto è mascherato da ‘package:purrr’:
discard
Il seguente oggetto è mascherato da ‘package:readr’:
col_factor
if(!require("ggplot2")){install.packages("ggplot2")}
library(leaflet)
Avvertimento: il pacchetto ‘leaflet’ è stato creato con R versione 4.2.3Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
library(dplyr)
library(MASS)
Caricamento pacchetto: ‘MASS’
Il seguente oggetto è mascherato da ‘package:dplyr’:
select
library(ggplot2)
library(RColorBrewer)
library(reticulate)
Avvertimento: il pacchetto ‘reticulate’ è stato creato con R versione 4.2.3
library(lime)
Caricamento pacchetto: ‘lime’
Il seguente oggetto è mascherato da ‘package:dplyr’:
explain
library(e1071)
Avvertimento: il pacchetto ‘e1071’ è stato creato con R versione 4.2.3
library(splines)
library(tidyverse)
library(data.table)
library(tseries)
Avvertimento: il pacchetto ‘tseries’ è stato creato con R versione 4.2.3Registered S3 method overwritten by 'quantmod':
method from
as.zoo.data.frame zoo
‘tseries’ version: 0.10-53
‘tseries’ is a package for time series analysis and computational finance.
See ‘library(help="tseries")’ for details.
library(mgcv)
Caricamento del pacchetto richiesto: nlme
Caricamento pacchetto: ‘nlme’
Il seguente oggetto è mascherato da ‘package:dplyr’:
collapse
This is mgcv 1.8-41. For overview type 'help("mgcv-package")'.
library(regclass)
Caricamento del pacchetto richiesto: bestglm
Caricamento del pacchetto richiesto: leaps
Caricamento del pacchetto richiesto: VGAM
Avvertimento: il pacchetto ‘VGAM’ è stato creato con R versione 4.2.3Caricamento del pacchetto richiesto: stats4
Caricamento pacchetto: ‘VGAM’
Il seguente oggetto è mascherato da ‘package:mgcv’:
s
Caricamento del pacchetto richiesto: rpart
Caricamento del pacchetto richiesto: randomForest
randomForest 4.7-1.1
Type rfNews() to see new features/changes/bug fixes.
Caricamento pacchetto: ‘randomForest’
Il seguente oggetto è mascherato da ‘package:ggplot2’:
margin
Il seguente oggetto è mascherato da ‘package:dplyr’:
combine
Important regclass change from 1.3:
All functions that had a . in the name now have an _
all.correlations -> all_correlations, cor.demo -> cor_demo, etc.
library(glmnet)
Avvertimento: il pacchetto ‘glmnet’ è stato creato con R versione 4.2.3Caricamento del pacchetto richiesto: Matrix
Caricamento pacchetto: ‘Matrix’
I seguenti oggetti sono mascherati da ‘package:tidyr’:
expand, pack, unpack
Loaded glmnet 4.1-6
library(coefplot)
Caricamento pacchetto: ‘coefplot’
Il seguente oggetto è mascherato da ‘package:e1071’:
extractPath
library(ggplot2)
Per accedere alle API di idealista necessitiamo di ottenere le credenziali. Una volta ottenute le carichiamo in R. Inoltre, prepariamo anche altri parametri necessari al collegamento con il sito.
# parametri in input
consumer_key <- "xop6jrf8yhw02a514zwhxrhlplvgn4ip"
consumer_secret <- "upiSxn5JmYpy"
# nuove credenziali
consumer_key = "hpsdfxg76unhb6tgwe38qukjzacwyr3b"
consumer_secret = "Ch7SVGGp4Vp4"
#Use basic authentication
secret <- jsonlite::base64_enc(paste(consumer_key, consumer_secret, sep = ":"))
req <- httr::POST("https://api.idealista.com/oauth/token",
httr::add_headers(
#"Authorization" = paste("Basic", gsub("n", "", secret)),
"Authorization" = paste("Basic", secret, sep = " "),
"Content-Type" = "application/x-www-form-urlencoded;charset=utf-8"
),
body = "grant_type=client_credentials"
)
token <- paste("Bearer", httr::content(req)$access_token)
Prepariamo i parametri in input che andranno a creare il link con la quale verrà eseguita la richiesta. Il nostro obiettivo è quello di scaricare tutti gli annunci delle case in vendita a Malaga. Come posizione è stata inserita la stazione Maria Zambrano ed stata impostata una distanza massima di 10 km. Come dimensione minima del locale è stato prefissato il valore di 30 per escludere eventuali annunci di garage.
#url user parameters
x = '36.71145256718129'
y = '-4.4288958904720355'
# x = '45.643170'
# y = '13.790524'
maxItems = '10000'
distance = '10000'
type = 'homes'
op = 'sale'
minprice = '30001'
maxprice = '200000000'
minsize = '30'
maxsize = '10000'
#url fixed parameters
site = 'https://api.idealista.com/3.5/es/search?'
# site = 'https://api.idealista.com/3.5/it/search?'
loc = 'center='
country = '&country=es'
# country = '&country=it'
maxitems = '&maxItems=50'
pages = '&numPage='
dist = '&distance='
property = '&propertyType='
operation = '&operation='
pricefrom = '&minPrice='
priceto = '&maxPrice='
misize = '&minSize='
masize = '&maxSize='
chalet = '&chalet=0'
Ora inoltreremo la richiesta di ricerca a idealista. Abbiamo un
limite mensile di massimo 100 richieste (pagina = 100), e
di massimo una richiesta al secondo (Sys.sleep(1)). Nel
ciclo a ogni giro viene generata una richiesta che differisce unicamente
sul numero della pagina dei risultati, andando così a prelevare tutti i
dati di una singola ricerca.
Una volta scaricati i dati ed estratti dal JSON otteremo delle liste che a sua volta dovranno essere estratte e immagazzinate in un dataframe. Il problema emerge in quanto all’interno della lista sono presenti sotto liste e, oltretutto, non per ogni annuncio. Allora bisogna creare una matrice che per ogni richiesta abbia il numero di colonne pari alla grandezza massima di variabili differenti per un’osservazione e successivamente riempita. Infine i dati vengono uniti ai dati delle richieste precedenti, aggiungendo le eventuali nuove colonne al database già esistente.
pagina = 100
for(z in 1:pagina)
{
print(z)
# prepara l'url
url <- paste(site, loc, x, ',', y, country, maxitems, pages, z, dist, distance,
property, type, operation, op, pricefrom, minprice, priceto, maxprice,
misize, minsize, masize, maxsize, sep = "")
# invia la richiesta a idealista
res <- httr::POST(url, httr::add_headers("Authorization" = token))
# estrai il contenuto dal JSON
cont_raw <- httr::content(res)
# Va a cercare l'item con più colonne
indexColMax = sapply(1:length(cont_raw[[1]]), function(x) cont_raw[[1]][[x]] %>% names() %>% length) %>% which.max
colNames = cont_raw[[1]][[indexColMax]] %>% names()
# Creo una matrice vuota dove imagazzinare i valori
m = matrix(NA, nrow = length(cont_raw[[1]]), ncol = length(colNames))
colnames(m) = colNames
for(r in 1:length(cont_raw[[1]]))
{
for(c in 1:length(cont_raw[[1]][[r]]))
{
# nel caso l'elemento della lista sia una sotto lista o df vado a spacchettarlo aggiungendo colonne
if(length(cont_raw[[1]][[r]][[c]])>1)
{
# non si può fare in un unico caso
for(i in 1:length(cont_raw[[1]][[r]][[c]]))
{
# se la colonna della sottolista non è già stata aggiunta lo faccio
if(is.null(names(cont_raw[[1]][[r]][[c]])))
{
cont_raw[[1]][[r]][[c]] = cont_raw[[1]][[r]][[c]][[1]]
}
if(!names(cont_raw[[1]][[r]][[c]])[i] %in% colNames)
{
colNames = c(colNames, names(cont_raw[[1]][[r]][[c]])[i])
m = cbind(m, rep(NA,length(cont_raw[[1]]))) # aggiunta della colonna
colnames(m) = colNames
}
}
# inserisco i dati della sottolista
for(k in 1:length(cont_raw[[1]][[r]][[c]]))
m[r,names(cont_raw[[1]][[r]][[c]])[k]] = cont_raw[[1]][[r]][[c]][[k]]
}else{
tryCatch(
{
m[r,names(cont_raw[[1]][[r]][c])] = ifelse(length(cont_raw[[1]][[r]][[c]][[1]])>1,
cont_raw[[1]][[r]][[c]][[1]][[1]],
cont_raw[[1]][[r]][[c]][[1]])
},
error = function(e) print(e, z, r, c))
}
}
}
data = m %>% data.frame() %>% tibble()
# debug
print(c(z,minprice,maxprice,data %>% dim))
# merge database
if(z == 1)
{
d = data
}else
{
data[setdiff(names(d), names(data))] <- NA
d[setdiff(names(d), names(data))] <- NA
d = bind_rows(d, data)
}
Sys.sleep(1)
}
saveRDS(data, "dati idealista")
Viene eseguita una pulizia dei dati grossolana, modificando principalmente il tipo di variabile.
data.frame(1:dim(data)[2],data %>% names)
# pulizia dei dati
data$floor[data$floor == "bj"] = 0
indexNumeric = c(1,4,5,6,9,11,12,19,20,23,29,30,43)
data = data %>% mutate_at(indexNumeric, as.numeric)
Avvertimento: There were 2 warnings in `mutate()`.
The first warning was:
ℹ In argument: `floor = .Primitive("as.double")(floor)`.
Caused by warning:
! NAs introduced by coercion
ℹ Run ]8;;ide:run:dplyr::last_dplyr_warnings()dplyr::last_dplyr_warnings()]8;; to see the 1 remaining warning.
indexFactor = c(7,8,14,15,16,17,18,26,31,39)
data = data %>% mutate_at(indexFactor, as.factor)
indexLogic = c(10,21,25,28,33:38,41,42)
data = data %>% mutate_at(indexLogic, as.logical)
data
Istogramma del piano delle case nella quale si trovano.
ggplot(data %>% subset(!is.na(floor)), aes(x = floor)) +
geom_histogram(bins = max(data$floor,na.rm = T)) +
scale_x_continuous(breaks = pretty_breaks(max(data$floor,na.rm = T)))
Grafico a barre del prezzo medio delle case in rapporto al piano nella quale si trovano.
Boxplot del prezzo medio delle case in funzione del piano nella quale si trovano.
Distribuzione della dimensione delle case.
Prezzo delle case in funzione della loro dimensione. Gli assi non sono proporzionali ma sono logaritmici.
Prezzo delle case in funzione al numero di bagni che la casa possiede.
Mappa del prezzo delle case nelle diverse zone della città. La mappa è interattiva, cliccando sui singoli pallini comparirà una box con ulteriori dati sulla casa.
pal = with(data, colorFactor(brewer.pal(10,"RdYlGn"), -price))
dfPopup = data %>%
mutate(popup_info = paste("Prezzo della casa: ", price, " $", "</br>",
"Superficie: ", size, "</br>",
"Piano: ", floor, "</br>",
"Numero di bagni: ", bathrooms, "</br>",
"Numero di camere: ", rooms, "</br>",
"Zona: ", neighborhood, "</br>",
"Distanza: ", distance, "</br>"))
leaflet() %>%
addTiles() %>%
addCircleMarkers(data = dfPopup,
lat = ~ latitude,
lng = ~ longitude,
radius = ~ 2,
opacity = .7,
color = ~ pal(-price),
popup = ~ popup_info)
Correlogramma delle variabili più frequenti.
modLasso = glmnet(makeX(data[, !names(data) %in% c("price","parkingSpace")] %>%
select_if(is.numeric) %>%
na.roughfix()),
data$price,
alpha = 1)
Error in glmnet(makeX(data[, !names(data) %in% c("price", "parkingSpace")] %>% :
x has missing values; consider using makeX() to impute them